package com.ybg.common.redis;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializer;
import redis.clients.jedis.JedisPoolConfig;

import java.time.Duration;
import java.util.concurrent.TimeUnit;

@Configuration
public class RedisConfig {
    @Value("${spring.redis.database}")
    private int database;
    @Value("${spring.redis.host}")
    private String host;
    @Value("${spring.redis.port}")
    private int port;
    @Value("${spring.redis.password}")
    private String password;

    @Value("${spring.redis.jedis.pool.min-idle}")
    private int minIdle;
    @Value("${spring.redis.jedis.pool.max-idle}")
    private int maxIdle;
    @Value("${spring.redis.jedis.pool.max-active}")
    private int maxActive;
    @Value("${spring.redis.jedis.pool.max-wait}")
    private int maxWait;

    @Value("${spring.redis.expiration}")
    private int expiration;
    @Value("${spring.redis.time-unit}")
    private String timeUnit;

    private JedisConnectionFactory connectionFactory(){
        // jedis连接池配置
        JedisPoolConfig poolConfig = new JedisPoolConfig();
        poolConfig.setMinIdle(minIdle);
        poolConfig.setMaxIdle(maxIdle);
        poolConfig.setMaxTotal(maxActive);
        poolConfig.setMaxWait(Duration.ofSeconds(maxWait));

        // 用池配置创建连接工厂
        JedisConnectionFactory connectionFactory = new JedisConnectionFactory(poolConfig);

        // 通过连接工厂的标准配置属性，配置连接
        RedisStandaloneConfiguration configuration = connectionFactory.getStandaloneConfiguration();
        configuration.setDatabase(database);
        configuration.setHostName(host);
        configuration.setPort(port);
        configuration.setPassword(password);
        connectionFactory.setUseSsl(false);
        // 通知连接工厂配置完成
        connectionFactory.afterPropertiesSet();

        return connectionFactory;
    }

    @Bean
    public RedisTemplate<String,Object> redisTemplate(){
        RedisTemplate<String,Object> template = new RedisTemplate<>();
        template.setConnectionFactory(connectionFactory());
        template.setKeySerializer(RedisSerializer.string());
        template.setHashKeySerializer(RedisSerializer.string());
        Jackson2JsonRedisSerializer<Object> valueSerializer = new Jackson2JsonRedisSerializer<Object>(Object.class);
        template.setValueSerializer(valueSerializer);
        template.setHashValueSerializer(valueSerializer);
        return template;
    }

    @Bean
    public RedisDao redisDao(@Autowired RedisTemplate<String,Object> template){
        try {
            // 匿名内部类
            return new RedisDao() {
                TimeUnit unit;

                // 普通代码块：发挥类似构造器的作用
                {
                    switch (timeUnit.toLowerCase()) {
                        case "h":
                            unit = TimeUnit.HOURS;
                            break;
                        case "m":
                            unit = TimeUnit.MINUTES;
                            break;
                        case "s":
                            unit = TimeUnit.SECONDS;
                            break;
                        default:
                            throw new RuntimeException("不支持的时间单位异常");
                    }
                }

                @Override
                public void setExpire(String key, Object value) {
                    template.opsForValue().set(key, value, expiration, unit);
                }

                @Override
                public <T> T getExpire(String key) {
                    Object obj = template.opsForValue().getAndExpire(key, expiration, unit);
                    return null == obj ? null : (T) obj;
                }

                @Override
                public boolean keyValid(String key) {
                    return template.hasKey(key);
                }

                @Override
                public void setHash(String key, String subKey, Object value) {
                    template.opsForHash().put(key, subKey, value);
                }

                @Override
                public <T> T getHash(String key, String subKey) {
                    Object obj = template.opsForHash().get(key, subKey);
                    return null == obj ? null : (T) obj;
                }

                @Override
                public boolean hashKeyValid(String key, String subKey) {
                    return template.opsForHash().hasKey(key,subKey);
                }
            };
        }finally {
            System.out.println("#### redis dao ok");
        }
    }

}
